package com.imooc.ad.handler;

import com.alibaba.fastjson.JSON;
import com.imooc.ad.dump.table.*;
import com.imooc.ad.index.DateTable;
import com.imooc.ad.index.IndexAware;
import com.imooc.ad.index.adplan.AdPlanIndex;
import com.imooc.ad.index.adplan.AdPlanObject;
import com.imooc.ad.index.adunit.AdUnitIndex;
import com.imooc.ad.index.adunit.AdUnitObject;
import com.imooc.ad.index.creative.CreativeIndex;
import com.imooc.ad.index.creative.CreativeObject;
import com.imooc.ad.index.creativeunit.CreativeUnitIndex;
import com.imooc.ad.index.creativeunit.CreativeUnitObject;
import com.imooc.ad.index.district.UnitDistrictIndex;
import com.imooc.ad.index.interest.UnitItIndex;
import com.imooc.ad.index.keyword.UnitKeywordIndex;
import com.imooc.ad.mysql.constant.OpType;
import com.imooc.ad.utils.CommonUtils;
import lombok.extern.slf4j.Slf4j;

import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;

/**
 * @Description:
 * @ClassName: AdLevelDataHandler
 * @Author: zhangzhongyu
 * @Date: 2019-10-16 11:43
 * @Version: 1.0
 */
@Slf4j
public class AdLevelDataHandler {

    // 1. 索引之间存在登记的划分，也就是依赖关系的划分
    // 2. 加载全量索引其实是增量索引，"添加"的一种特殊实现
    // 利用Index实现增删改查

    // 第二层级索引，是因为不与其他的索引服务有依赖关系，其他的索引可能依赖他们，他们不会依赖其他索引
    //2.1 第二层级索引，对应的推广计划的索引
    public static void handleLevel2(AdPlanTable planTable, OpType type) {

        AdPlanObject planObject = new AdPlanObject(
                planTable.getId(),
                planTable.getUserId(),
                planTable.getPlanStatus(),
                planTable.getStartTime(),
                planTable.getEndTime()
        );
        handleBinLogEvent(
                DateTable.of(AdPlanIndex.class),
                planObject.getPlanId(),
                planObject,
                type
        );
    }

    // 2.2 第二层级索引，对创意这个对象进行索引
    public static void handleLevel2(AdCreativeTable creativeTable,
                                     OpType type) {
        CreativeObject creativeObject = new CreativeObject(
                creativeTable.getAdId(),
                creativeTable.getName(),
                creativeTable.getType(),
                creativeTable.getMaterialType(),
                creativeTable.getHeight(),
                creativeTable.getWidth(),
                creativeTable.getAuditStatus(),
                creativeTable.getAdUrl()
        );
        handleBinLogEvent(
                DateTable.of(CreativeIndex.class),
                creativeObject.getAdId(),
                creativeObject,
                type
        );
    }

    // 第三层级的数据表索引，就是与第二层级有依赖关系，比如AdUnit对AdPlan有依赖
    // 还包括Creative与Unit的关系表，因为Creative不仅依赖Creative本身，还依赖于第三层级Unit
    // 3.1 第三层级，推广单元索引的构造
    public static void handleLevel3(AdUnitTable unitTable, OpType type) {
        AdPlanObject adPlanObject = DateTable.of(
                AdPlanIndex.class
        ).get(unitTable.getPlanId());

        if (null == adPlanObject) {
            log.error("handleLevel3 found AdPlanObject error: {}", unitTable.getPlanId());
            return;
        }

        AdUnitObject unitObject = new AdUnitObject(
                unitTable.getUnitId(),
                unitTable.getUnitStatus(),
                unitTable.getPositionType(),
                unitTable.getPlanId(),
                adPlanObject
        );
        handleBinLogEvent(
                DateTable.of(AdUnitIndex.class),
                unitObject.getUnitId(),
                unitObject,
                type
        );
    }

    // 3.2 第三层级 创意与推广单元关联关系表索引关系构造
    public static void handleLevel3(AdCreativeUnitTable creativeUnitTable, OpType type) {
        if (type == OpType.UPDATE) {
            log.error("CreativeUnitIndex not support update");
            return;
        }

        AdUnitObject unitObject = DateTable.of(
                AdUnitIndex.class
        ).get(creativeUnitTable.getUnitId());
        CreativeObject creativeObject = DateTable.of(
                CreativeIndex.class
        ).get(creativeUnitTable.getAdId());

        if (null == unitObject || null == creativeObject) {
            log.error("AdCreativeUnitTable index error: {}",
                    JSON.toJSONString(creativeUnitTable));
            return;
        }

        CreativeUnitObject creativeUnitObject = new CreativeUnitObject(
                creativeUnitTable.getAdId(),
                creativeUnitTable.getUnitId()
        );
        handleBinLogEvent(
                DateTable.of(CreativeUnitIndex.class),
                CommonUtils.stringConcat(
                        creativeUnitObject.getAdId().toString(),
                        creativeUnitObject.getUnitId().toString()
                ),
                creativeUnitObject,
                type
        );
    }

    // 第四层级的索引，主要添加了关键词维度、兴趣维度、地域维度的限制，
    // 对第三层级的推广单元有依赖关系
    // 4.1 第四层级，处理地域对象
    public static void handleLevel4(AdUnitDistrictTable unitDistrictTable,
                                    OpType type) {
        if (type == OpType.UPDATE) {
            log.error("district index can not support update");
            return;
        }

        AdUnitObject unitObject = DateTable.of(
                AdUnitIndex.class
        ).get(unitDistrictTable.getUnitId());
        if (null == unitObject) {
            log.error("AdUnitDistrictTable index error: {}",
                    unitDistrictTable.getUnitId());
            return;
        }

        String key = CommonUtils.stringConcat(
                unitDistrictTable.getProvince(),
                unitDistrictTable.getCity()
        );
        Set<Long> value = new HashSet<>(
                // 创建一个元素的Set
                Collections.singleton(unitDistrictTable.getUnitId())
        );
        handleBinLogEvent(
                DateTable.of(UnitDistrictIndex.class),
                key,
                value,
                type
        );
    }

    // 4.2 第四层级，
    public static void handleLevel4(AdUnitItTable unitItTable, OpType type) {
        if (type == OpType.UPDATE) {
            log.error("it index can not support update");
            return;
        }
        AdUnitObject unitObject = DateTable.of(
                AdUnitIndex.class
        ).get(unitItTable.getUnitId());
        if (null == unitObject) {
            log.error("AdUnitItTable index error: {}", unitItTable.getUnitId());
            return;
        }

        Set<Long> value = new HashSet<>(
                Collections.singleton(unitItTable.getUnitId())
        );
        handleBinLogEvent(
                DateTable.of(UnitItIndex.class),
                unitItTable.getItTag(),
                value,
                type
        );
    }

    // 4.3 第四层级，关键词和推广单元关系
    public static void handleLevel4(AdUnitKeywordTable unitKeywordTable, OpType type) {
        if (type == OpType.UPDATE) {
            log.error("keyword index can not support update");
            return;
        }
        AdUnitObject unitObject = DateTable.of(
                AdUnitIndex.class
        ).get(unitKeywordTable.getUnitId());
        if (null == unitObject) {
            log.error("AdUnitKeywordTable index error: {}", unitKeywordTable.getUnitId());
            return;
        }

        Set<Long> value = new HashSet<>(
                Collections.singleton(unitKeywordTable.getUnitId())
        );
        handleBinLogEvent(
                DateTable.of(UnitKeywordIndex.class),
                unitKeywordTable.getKeyword(),
                value,
                type
        );
    }





    //
    private static <K, V> void handleBinLogEvent(IndexAware<K, V> index,
                                                 K key,
                                                 V value,
                                                 OpType type) {
        switch (type) {
            case ADD:
                index.add(key, value);
                break;
            case UPDATE:
                index.update(key, value);
                break;
            case DELETE:
                index.delete(key, value);
                break;
            default:
                break;
        }
    }



}
